package api

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"hcy-api/lib/http"
	"hcy-api/structs/constant"
	"hcy-api/structs/enum"
	"hcy-api/structs/idp"
	"hcy-api/structs/tables"
	"idp/global"
	"idp/listener"
	"idp/service"
	"time"
)

var ClientApi = new(clientApi)

type clientApi struct {
}

func (api clientApi) Page(c *gin.Context) {
	var in idp.SearchClientPage
	if err := c.ShouldBindQuery(&in); err != nil {
		http.BadWithParamsError(c)
		return
	}
	self := http.GetCurrentUser(c)
	li, total, err := service.ClientService.Page(in, self.UserID, self.AccountLv)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.OkPage(c, li, total)
}

func (api clientApi) List(c *gin.Context) {
	self := http.GetCurrentUser(c)
	li, err := service.ClientService.List(self.UserID, self.AccountLv)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.Ok(c, li)
}
func (api clientApi) GetDetail(c *gin.Context) {
	in := struct {
		LogType  string `form:"logType"`
		ClientId int64  `form:"clientId,string"`
	}{}
	if err := c.ShouldBindQuery(&in); err != nil {
		http.BadWithParamsError(c)
		return
	}
	r, err := service.ClientService.SelectLastLog(in.LogType, in.ClientId)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.Ok(c, r)
}

func (api clientApi) Distribution(c *gin.Context) {
	var in idp.ClientBindBranchDto
	if err := c.ShouldBindJSON(&in); err != nil {
		http.BadWithParamsError(c)
		return
	}
	self := http.GetCurrentUser(c)
	if self.AccountLv != tables.AccountLvForRoot {
		http.BadWithCode(c, enum.ErrorMap.AccessDeniedForLV)
		return
	}
	err := global.DB.Transaction(func(tx *gorm.DB) error {
		err := tx.Where("client_id in ?", in.ClientIds).Delete(&tables.IdpMapBranchClient{}).Error
		if err != nil {
			return err
		}
		li := make([]tables.IdpMapBranchClient, 0)
		for _, v := range in.ClientIds {
			li = append(li, tables.IdpMapBranchClient{
				ClientId: v,
				BranchId: in.BranchId,
			})
		}
		if len(li) > 0 {
			err = tx.Model(&tables.IdpMapBranchClient{}).CreateInBatches(&li, len(li)).Error
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.OK204(c)
}
func (api clientApi) ExecPlugin(c *gin.Context) {
	var in idp.ExecPluginDto
	if err := c.ShouldBindJSON(&in); err != nil {
		http.BadWithParamsError(c)
		return
	}
	if !listener.IsOnline(in.ClientId) {
		http.BadWithCode(c, enum.ErrorMap.ClientIsOff)
		return
	}
	key := fmt.Sprintf("result_%d_%s_%v", in.ClientId, in.Cmd, in.Argus)
	global.InstructResultMap.Store(key, "")
	err := listener.SendInstruct(in.ClientId, constant.ExecutePlugin, in.Cmd, in.Argus)
	if err != nil {
		global.InstructResultMap.Delete(key)
		http.BadWithCode(c, enum.ErrorMap.SendMsgErr)
		return
	}
	t := time.Now().Unix() + 5
	var val any
	for true {
		if time.Now().Unix() > t {
			global.InstructResultMap.Delete(key)
			http.BadWithCode(c, enum.ErrorMap.InstructionResponseTimeOut)
			return
		}
		if result, ok := global.InstructResultMap.Load(key); ok {
			if result != "" {
				val = result
				global.InstructResultMap.Delete(key)
				http.Ok(c, val)
				return
			}
		}
	}
}

func (api clientApi) FreeList(c *gin.Context) {
	var in idp.SearchClientPage
	if err := c.ShouldBindQuery(&in); err != nil {
		http.BadWithParamsError(c)
		return
	}
	li, total, err := service.ClientService.FreeList(in)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.OkPage(c, li, total)
}
